package com.bobo.web.provider.util.commutils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.DeserializationConfig.Feature;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 实现描述:
 *
 * @author steven
 * @version v1.0.0
 * @see
 * @since 2017/1/2 上午11:16
 */
@Component
public class JacksonUtils {

    private static final Logger logger = LoggerFactory.getLogger(JacksonUtils.class);

    private static final class JsonUtilContainer {
        private static final JacksonUtils instances = new JacksonUtils();
    }

    private static ObjectMapper objectMapper;

    static {
        objectMapper = generateMapper(Inclusion.ALWAYS);
    }

    public static JacksonUtils getInstance() {
        return JsonUtilContainer.instances;
    }

    private JacksonUtils() {
    }

    @SuppressWarnings("unused")
    private String filterJson(String json) {
        return json.replaceAll("\"", "'");
    }

    public JsonNode parseObject(String jsonStr) {
        try {
            return objectMapper.readTree(jsonStr);
        } catch (Exception e) {
            String message = String.format("jsonString to JsonNode error;jsonString=%s", jsonStr);
            logger.error(message, e);
            return null;
        }
    }

    /**
     * 获取泛型的Collection Type
     * @param jsonStr json字符串
     * @param collectionClass 泛型的Collection
     * @param elementClasses 元素类型
     */
    public <T> T readJson(String jsonStr, Class<?> collectionClass, Class<?>... elementClasses) {
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
        try {
            return objectMapper.readValue(jsonStr, javaType);
        } catch (Exception e) {
            String message = String.format("jsonString to Object error;jsonString=%s", jsonStr);
            logger.error(message, e);
            return null;
        }
    }

    /**
     * 将json通过类型转换成对象
     *
     * @param json json字符串
     * @param clazz 泛型类型
     * @return 返回对象
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public <T> T readJson(String json, Class<T> clazz) {
        if (StringUtils.isBlank(json) || clazz == null) {
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T) json : objectMapper.readValue(json, clazz);
        } catch (Exception e) {
            String message = String.format("jsonString to Object error;jsonString=%s", json);
            logger.error(message, e);
            return null;
        }
    }

    /**
     * 将json通过类型转换成对象
     * @param json json字符串
     * @param typeReference 引用类型
     * @return 返回对象
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public <T> T readJson(String json, TypeReference<?> typeReference) {
        if (StringUtils.isBlank(json) || typeReference == null) {
            return null;
        }
        try {
            return (T) (typeReference.getType().equals(String.class) ? json : objectMapper.readValue(json, typeReference));
        } catch (Exception e) {
            String message = String.format("jsonString to Object error;jsonString=%s", json);
            logger.error(message, e);
            return null;
        }
    }

    /**
     * 将对象转换成json
     *
     * <pre>
     *     {@link JacksonUtils JacksonUtils}.toJson(user);
     * </pre>
     *
     * @return 返回json字符串
     * @throws IOException
     */
    public <T> String toJson(T object) {
        if (object == null) {
            return "";
        }
        try {
            return object instanceof String ? (String) object : objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            String message = String.format("Object to jsonString error;object=%s", object.getClass());
            logger.error(message, e);
            return null;
        }
    }

    /**
     * 将对象转换成json, 可以设置输出属性
     *
     * <pre>
     *     {@link JacksonUtils JacksonUtils}.toJson(user, {@link Inclusion Inclusion.ALWAYS});
     * </pre>
     *
     * {@link Inclusion Inclusion 对象枚举}
     * <ul>
     * <li>{@link Inclusion Inclusion.ALWAYS 全部列入}</li>
     * <li>{@link Inclusion Inclusion.NON_DEFAULT 字段和对象默认值相同的时候不会列入}</li>
     * <li>{@link Inclusion Inclusion.NON_EMPTY 字段为NULL或者""的时候不会列入}</li>
     * <li>{@link Inclusion Inclusion.NON_NULL 字段为NULL时候不会列入}</li>
     * </ul>
     *
     * @param src 对象
     * @param inclusion 传入一个枚举值, 设置输出属性
     * @return 返回json字符串
     * @throws IOException
     */
    public <T> String toJson(T src, Inclusion inclusion) throws IOException {
        if (src instanceof String) {
            return (String) src;
        } else {
            ObjectMapper customMapper = generateMapper(inclusion);
            return customMapper.writeValueAsString(src);
        }
    }

    /**
     * 将对象转换成json, 传入配置对象
     *
     * <pre>
     *     {@link ObjectMapper ObjectMapper} mapper = new ObjectMapper();
     *     mapper.setSerializationInclusion({@link Inclusion Inclusion.ALWAYS});
     *     mapper.configure({@link Feature Feature.FAIL_ON_UNKNOWN_PROPERTIES}, false);
     *     mapper.configure({@link Feature Feature.FAIL_ON_NUMBERS_FOR_ENUMS}, true);
     *     mapper.setDateFormat(new {@link SimpleDateFormat SimpleDateFormat}("yyyy-MM-dd HH:mm:ss"));
     *     {@link JacksonUtils JacksonUtils}.toJson(user, mapper);
     * </pre>
     *
     * {@link ObjectMapper ObjectMapper}
     *
     * @see ObjectMapper
     *
     * @param src 对象
     * @param mapper 配置对象
     * @return 返回json字符串
     * @throws IOException
     */
    public <T> String toJson(T src, ObjectMapper mapper) throws IOException {
        if (null != mapper) {
            if (src instanceof String) {
                return (String) src;
            } else {
                return mapper.writeValueAsString(src);
            }
        } else {
            return null;
        }
    }

    /**
     * 返回{@link ObjectMapper ObjectMapper}对象, 用于定制性的操作
     *
     * @return {@link ObjectMapper ObjectMapper}对象
     */
    public static ObjectMapper mapper() {
        return objectMapper;
    }

    /**
     * 通过Inclusion创建ObjectMapper对象
     *
     * {@link Inclusion Inclusion 对象枚举}
     * <ul>
     * <li>{@link Inclusion Inclusion.ALWAYS 全部列入}</li>
     * <li>{@link Inclusion Inclusion.NON_DEFAULT 字段和对象默认值相同的时候不会列入}</li>
     * <li>{@link Inclusion Inclusion.NON_EMPTY 字段为NULL或者""的时候不会列入}</li>
     * <li>{@link Inclusion Inclusion.NON_NULL 字段为NULL时候不会列入}</li>
     * </ul>
     *
     * @param inclusion 传入一个枚举值, 设置输出属性
     * @return 返回ObjectMapper对象
     */
    private static ObjectMapper generateMapper(Inclusion inclusion) {

        ObjectMapper customMapper = new ObjectMapper();

        // 设置输出时包含属性的风格
        customMapper.setSerializationInclusion(inclusion);

        // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
        customMapper.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 禁止使用int代表Enum的order()來反序列化Enum,非常危險
        customMapper.configure(Feature.FAIL_ON_NUMBERS_FOR_ENUMS, true);

        // 所有日期格式都统一为以下样式
        customMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        customMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);// 取消默认转换timestamps形式;

        return customMapper;
    }

    @SuppressWarnings("unchecked")
    @Deprecated
    public static <T> T convertToBean(Class<T> clazz, Object val) {
        if(val == null) return null;
        if(val instanceof Map) {
            return (T) val;
        }
        return JSON.parseObject(beanToText(val), clazz);
    }

    @Deprecated
    public static <T> List<T> convertToBeanArray(Class<T> clazz, Object val) {
        if(val == null) return new ArrayList<T>();
        return JSON.parseArray(beanToText(val), clazz);
    }

    @Deprecated
    public static String beanToText(Object bean) {
        if(bean == null) return null;
        if(bean instanceof String) {
            return (String) bean;
        }
        return JSON.toJSONString(bean);
    }

    /**
     * 反序列化为对象
     * @param json
     * @param targetClass
     * @param <T>
     * @return
     * @throws IOException
     */

    public static <T> T unmarshalFromString(String json, Class<T> targetClass)  {
        if(StringUtils.isBlank(json)||targetClass==null)
            return null;

        try {
            return objectMapper.readValue(json,targetClass);
        } catch (Exception e) {
            logger.error(String.format("unmarshalFromString error %s, %s", json, targetClass.toString()), e);

        }
        return null;
    }
}
